#include "stm.h"
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>

#define CNAME "mystm"
struct i2c_client* cli = NULL;
struct spi_device* cspi = NULL;

// 分布实现字符设备相关
struct cdev* cdev = NULL;
dev_t devn = -1;

// 自动创建设备节点相关
struct class* cls = NULL;
struct device* dev = NULL;

struct work_struct work; // 分配工作队列对象

int dat = 0;
const struct of_device_id m74hc595_match_table[] = {
    { .compatible = "hqyj,m74hc595" },
    {}
};
// 中断底半部处理函数
void work_func(struct work_struct* work1)
{
    int a, b, c, d;
    a = dat / 1000;
    b = dat / 100 % 10;
    c = dat / 10 % 10;
    d = dat % 10;
    spi_write(cspi, which + 0, 1);
    spi_write(cspi, code + a, 1);
    mdelay(1);
    spi_write(cspi, which + 1, 1);
    spi_write(cspi, code + b, 1);
    mdelay(1);
    spi_write(cspi, which + 2, 1);
    spi_write(cspi, code + c, 1);
    mdelay(1);
    spi_write(cspi, which + 3, 1);
    spi_write(cspi, code + d, 1);
    mdelay(1);
    // printk("a=%d b=%d c=%d d=%d\n",a,b,c,d);
    // mdelay(1000);
    schedule_work(&work); // 调用中断底半部执行
}

int m74hc595_probe(struct spi_device* spi)
{
    printk("__%d__:%s:%s\n", __LINE__, __func__, __FILE__);
    cspi = spi;
    INIT_WORK(&work, work_func); // 对象初始化
    return 0;
}
int m74hc595_remove(struct spi_device* spi)
{
    printk("__%d__:%s:%s\n", __LINE__, __func__, __FILE__);
    cancel_work_sync(&work); // 取消工作队列
    return 0;
}
struct spi_driver m74hc595 = {
    .probe = m74hc595_probe,
    .remove = m74hc595_remove,
    .driver = {
        .name = "xxxx",
        .of_match_table = m74hc595_match_table,
    },
};

// 读取温湿度
int read_temp_hum(unsigned char cmd)
{
    unsigned short data = 0, ret = 0;
    // 封装读消息结构体
    struct i2c_msg r_msg[] = {
        {
            .addr = cli->addr,
            .flags = 0,
            .len = 1,
            .buf = &cmd,
        },
        {
            .addr = cli->addr,
            .flags = 1,
            .len = 2,
            .buf = (u8*)&data,

        },
    };

    // 发送消息结构体
    if (i2c_transfer(cli->adapter, r_msg, ARRAY_SIZE(r_msg)) != ARRAY_SIZE(r_msg)) {
        printk("__%d__:i2c_transfer is error\n", __LINE__);
        return -1;
    }
    ret |= (data >> 8);
    ret |= (data << 8);
    return ret;
}

int close(struct inode* inode, struct file* file)
{
    char buf[]={0xf,0x0};
    printk("__%d__:%s:%s\n", __LINE__, __func__, __FILE__);
    cancel_work_sync(&work); // 取消工作队列
    spi_write(cspi,buf,2);
    return 0;
}
long ioctl(struct file* file, unsigned int cmd, unsigned long args)
{
    int ret = -1;

    switch (cmd) {
    case GET_SI7006_HUM:
        ret = read_temp_hum(0xE5);
        if (copy_to_user((void*)args, &ret, _IOC_SIZE(cmd))) {
            printk("copy_to_user is error\n");
            return -1;
        }
        break;
    case GET_SI7006_TMEP:
        ret = read_temp_hum(0xE3);
        if (copy_to_user((void*)args, &ret, _IOC_SIZE(cmd))) {
            printk("copy_to_user is error\n");
            return -1;
        }
        break;
    case SEG_DAT:
        dat = (int)args;
        break;
    }

    schedule_work(&work); // 调用中断底半部执行
    return 0;
}

const struct file_operations fops = {
    .unlocked_ioctl = ioctl,
    .release = close,
};

// 设备驱动与总线驱动匹配成功时调用
int probe(struct i2c_client* client, const struct i2c_device_id* id)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    cli = client;

    /**********分布实现字符设备**************/
    cdev = cdev_alloc();
    if (!cdev) {
        printk("__%d__:cdev_alloc is error\n", __LINE__);
        goto ERR1;
    }
    cdev_init(cdev, &fops); // 初始化对象
    // 动态分配对象
    if (alloc_chrdev_region(&devn, 0, 1, CNAME)) {
        printk("__%d__:alloc_chrdev_region is error\n", __LINE__);
        goto ERR2;
    }
    // 注册对象
    if (cdev_add(cdev, devn, 1)) {
        printk("__%d__:cdev_add is error\n", __LINE__);
        goto ERR3;
    }
    /**********自动创建设备节点**************/
    cls = class_create(THIS_MODULE, CNAME);
    if (IS_ERR(cls)) {
        printk("__%d__:class_create is error\n", __LINE__);
        goto ERR4;
    }
    dev = device_create(cls, NULL, devn, NULL, CNAME);
    if (IS_ERR(dev)) {
        printk("__%d__:device_create is error\n", __LINE__);
        goto ERR5;
    }

    spi_register_driver(&m74hc595); // 注册m74hc595
    return 0;

ERR5:
    class_destroy(cls);
ERR4:
    cdev_del(cdev);
ERR3:
    unregister_chrdev_region(devn, 1);
ERR2:
    kfree(cdev);
ERR1:
    return -1;
}

// 设备驱动与总线驱动分离时调用
int remove(struct i2c_client* client)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    /*******************取消字符设备******************/
    device_destroy(cls, devn);
    class_destroy(cls);
    cdev_del(cdev); // 注销对象
    unregister_chrdev_region(devn, 1);
    kfree(cdev);
    /***********************************************/

    spi_unregister_driver(&m74hc595); // 注销m74hc595
    return 0;
}
const struct of_device_id match_table[] = {
    { .compatible = "hqyj,si7006" },
    {},
};
struct i2c_driver idri = {
    .probe = probe,
    .remove = remove,
    .driver = {
        .name = "xxxx",
        .of_match_table = match_table,
    },

};
module_i2c_driver(idri); // 一键注册注销宏
MODULE_LICENSE("GPL");